/**
  ******************************************************************************
  * @file    ring_buffer.c
  * @author  ashuai0110
  * @version V2.1
  * @date    2023-09-24
  * @brief   环形缓冲区
  *          (适合定长或易分离出的数据,写满后再写会覆写旧数据无论其是否被读出处理过)
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "ring_buffer.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup ring_buffer ring_buffer
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/
/**
 * @defgroup ring_buffer_local_macros ring buffer local macros
 * @{
 */

/**
 * @defgroup ring_buffer_check_parameters_validity ring buffer check parameters validity
 * @{
 */
/* 环形缓冲区数据存储区大小有效性检查 */
#define IS_VALID_RB_SIZE(x)                                                   \
(       (x) != 0u)
/**
 * @}
 */

/**
 * @}
 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
 * @defgroup ring_buffer_global_functions ring buffer global functions
 * @{
 */

/**
  * @brief  环形缓冲区初始化
  *
  * @note   None
  *
  * @param  _rb  : 环形缓冲区实例
  *
  * @param  pBuf : 数据存储区
  *
  * @param  size : 缓冲区最大填充数量(数据存储区大小byte)
  *
  * @retval None
  */
void ring_buffer_init(ring_buffer_t *_rb, void *pBuf, uint32_t size)
{
    ASSERT_PARAM(IS_VALID_POINT(_rb));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    ASSERT_PARAM(IS_VALID_RB_SIZE(size));

    _rb->pBuf = (char *)pBuf;
    _rb->pHead = _rb->pBuf;
    _rb->pTail = _rb->pBuf;
    _rb->size = size;
}

/**
  * @brief  环形缓冲区取消初始化
  *
  * @note   恢复默认
  *
  * @param  _rb : 环形缓冲区实例
  *
  * @retval None
  */
void ring_buffer_de_init(ring_buffer_t *_rb)
{
    ASSERT_PARAM(IS_VALID_POINT(_rb));

    memset(_rb, 0, sizeof(ring_buffer_t));
}

/**
  * @brief  获取环形缓冲区的大小
  *
  * @note   缓冲区大小(byte)
  *
  * @param  _rb : 环形缓冲区实例
  *
  * @retval 环形缓冲区的大小
  */
uint32_t ring_buffer_total_size(ring_buffer_t *_rb)
{
    ASSERT_PARAM(IS_VALID_POINT(_rb));

    return _rb->size;
}

/**
  * @brief  获取环形缓冲区的可读大小
  *
  * @note   待读出数量(byte)
  *
  * @param  _rb : 环形缓冲区实例
  *
  * @retval 环形缓冲区的可读大小
  */
uint32_t ring_buffer_can_read(ring_buffer_t *_rb)
{
    ASSERT_PARAM(IS_VALID_POINT(_rb));
    
    if(_rb->pHead > _rb->pTail)
    {
        return (ring_buffer_total_size(_rb) - (_rb->pHead - _rb->pTail));
    }
    else if(_rb->pHead < _rb->pTail)
    {
        return (_rb->pTail - _rb->pHead);
    }

    return 0;
}

/**
  * @brief  获取环形缓冲区的可写大小
  *
  * @note   可写入数量(byte)
  *
  * @param  _rb : 环形缓冲区实例
  *
  * @retval 环形缓冲区的可写大小
  */
uint32_t ring_buffer_can_write(ring_buffer_t *_rb)
{
    ASSERT_PARAM(IS_VALID_POINT(_rb));
    
    return (ring_buffer_total_size(_rb) - ring_buffer_can_read(_rb));
}

/**
  * @brief  从环形缓冲区读出数据
  *
  * @note   None
  *
  * @param  _rb   : 环形缓冲区实例
  *
  * @param  pBuf  : 读出数据的存储区
  *
  * @param  size  : 读出数据大小
  *
  * @retval uint8_t
  *    @arg RET_OK  : 读出成功
  *    @arg RET_ERR : 参数size为0或超出可读大小
  */
uint8_t ring_buffer_read(ring_buffer_t *_rb, void *pBuf, uint32_t size)
{
    uint32_t readSize = 0;
    
    ASSERT_PARAM(IS_VALID_POINT(_rb));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    if(0 == size && size > ring_buffer_total_size(_rb)) { return RET_ERR; }

    if(_rb->pHead < _rb->pTail)
    {
        memcpy(pBuf, _rb->pHead, size);
        _rb->pHead += size;
    }
    else
    {
        readSize = ring_buffer_total_size(_rb) - (_rb->pHead - _rb->pBuf);
        if(size < readSize)
        {
            memcpy(pBuf, _rb->pHead, size);
            _rb->pHead += size;
        }
        else
        {
            memcpy(pBuf, _rb->pHead, readSize);
            _rb->pHead = _rb->pBuf;
            ring_buffer_read(_rb, (void *)((char *)pBuf + readSize), size - readSize);
        }
    }

    return RET_OK;
}

/**
  * @brief  写入数据到环形缓冲区
  *
  * @note   None
  *
  * @param  _rb   : 环形缓冲区实例
  *
  * @param  pData : 写入数据的存储区
  *
  * @param  size  : 写入数据的大小
  *
  * @retval uint8_t
  *    @arg RET_OK  : 写入成功
  *    @arg RET_ERR : 参数size为0或超出可写大小
  */
uint8_t ring_buffer_write(ring_buffer_t *_rb, void *pData, uint32_t size)
{
    uint32_t writeSize = 0;
    
    ASSERT_PARAM(IS_VALID_POINT(_rb));
    ASSERT_PARAM(IS_VALID_POINT(pData));
    
    if(0 == size || size > ring_buffer_total_size(_rb)) { return RET_ERR; }

    if(_rb->pHead <= _rb->pTail)
    {
        writeSize = ring_buffer_total_size(_rb) - (_rb->pTail - _rb->pBuf);
        if (size <= writeSize)
        {
            memcpy(_rb->pTail, pData, size);
            _rb->pTail += size;
            if(_rb->pTail >= (_rb->pBuf + ring_buffer_total_size(_rb))) { _rb->pTail = _rb->pBuf; }
        }
        else
        {
            memcpy(_rb->pTail, pData, writeSize);
            _rb->pTail = _rb->pBuf;
            ring_buffer_write(_rb, (void *)((char *)pData + writeSize), size - writeSize);
        }
    }
    else
    {
        memcpy(_rb->pTail, pData, size);
        _rb->pTail += size;
    }

    return RET_OK;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
